#include "test_asocket.h"
#include "cm_uart.h"
#include "cm_demo_uart.h"
#include "cm_eloop.h"
//#include "cm_etimer.h"
#include "inet6.h"
#include "cm_asocket.h"

#include "test_ssl.h"

extern ssl_ctx cm_ssl_ctx_p;
extern int con_flag;
static cm_eloop_handle_t eloop;
static int socket = -1;
int socket_arr[4] = {0,0,0,0};
static uint8_t recv_buf[16000] = {0};
//static cm_etimer_manager_t test_etimer_manager = {NULL};
//static cm_etimer_t test_etimers[10];
/* 异步socket消息回调(执行环境为eloop线程) */
static int asocket_connect_flag = 0;
static void test_asocket_event(int sock, cm_asocket_event_e event, void *user_param)
{
    switch (event)
    {
    // responses
    case CM_ASOCKET_EV_CONNECT_OK: {
        cm_demo_printf("sock(%d) connect_ok\n", sock);
        asocket_connect_flag = 1;
        break;
    }
    case CM_ASOCKET_EV_CONNECT_FAIL: {
        cm_demo_printf("sock(%d) connect_fail\n", sock);
        asocket_connect_flag = 0;
        break;
    }

    // indications
    case CM_ASOCKET_EV_RECV_IND: {
        /* 取得获取接收缓存中可读的数据长度 */
        int recv_avail = 0;
        cm_asocket_ioctl(sock, FIONREAD, &recv_avail);

        /* 接收数据 */

        int ret = -1;
        if(1 == con_flag)
        {
            //ret = cm_asocket_recv(sock, recv_buf, 0, 0);
        }
        else
        {
            ret = cm_asocket_recv(sock, recv_buf, sizeof(recv_buf), 0);
        }
        if ((ret > 0) && (0 == con_flag))
        {
            //cm_demo_printf("sock(%d) recv_ind: recv_avail=%d, recv_len=%d, data=%.*s\n", sock, recv_avail, ret, ret, recv_buf);
            int pos = 0;
            cm_demo_printf("sock(%d) recv_ind: recv_avail=%d, recv_len=%d\n", sock, recv_avail, ret);
            for(;pos < recv_avail;)
            {
                if(256 > recv_avail)
                {
                    cm_uart_write(OPENCPU_MAIN_URAT, recv_buf, recv_avail, 1000);
                    goto over;
                }
                cm_uart_write(OPENCPU_MAIN_URAT, &recv_buf[pos], 256, 1000);
                pos+=256;
                if((pos+256)>recv_avail)
                {
                    cm_uart_write(OPENCPU_MAIN_URAT, &recv_buf[pos - 256], recv_avail - pos + 256, 1000);
                    goto over;
                }
            }
over:       ;
            cm_demo_printf("\n");
        }
        else
        {
            cm_demo_printf("sock(%d) recv_ind error(%d)\n", sock, errno);

            if (ENOTCONN == errno)
            {
                /* Connection closed */
                cm_demo_printf("sock(%d) recv_ind: Connection closed\n", sock);
            }
        }
        break;
    }
    case CM_ASOCKET_EV_SEND_IND:
        cm_demo_printf("sock(%d) send_ind\n", sock);
        break;
    case CM_ASOCKET_EV_ACCEPT_IND:
        cm_demo_printf("sock(%d) accept_ind\n", sock);
        break;
    case CM_ASOCKET_EV_ERROR_IND: {
        /* 获取socket错误码 */
        int sock_error = 0;
        socklen_t opt_len = sizeof(sock_error);
        cm_asocket_getsockopt(sock, SOL_SOCKET, SO_ERROR, &sock_error, &opt_len);
        cm_demo_printf("sock(%d) error_ind: sock_error(%d)\n", sock, sock_error);
        if (ECONNABORTED == sock_error)
        {
            /* Connection aborted */
            cm_demo_printf("sock(%d) error_ind: Connection aborted\n", sock);
        }
        else if (ECONNRESET == sock_error)
        {
            /* Connection reset */
            cm_demo_printf("sock(%d) error_ind: Connection reset\n", sock);
        }
        else if (ENOTCONN == sock_error)
        {
            /* Connection closed */
            cm_demo_printf("sock(%d) error_ind: Connection closed\n", sock);
        }
        break;
    }
    default:
        break;
    }
}
/* eloop执行线程 */
static void eloop_thread_proc(void *argument)
{
    cm_log_printf(0, "__eloop_thread_proc\n");
    /* 启动事件循环 */
    while (1)
    {
        //uint32_t wait_time = cm_etimer_get_wait_time(&test_etimer_manager);
        //cm_demo_printf("wait time:%u\n",wait_time);
        //int ret = cm_eloop_wait_event(eloop, wait_time);
        int ret = cm_eloop_wait_event(eloop, CM_ELOOP_WAIT_FOREVER);
        if (ret < 0)
        {
            break;
        }
        //cm_etimer_run(&test_etimer_manager);

        // int times = 0;
        // while(!asocket_connect_flag)
        // {
        //    osDelay(100);
        //     times++;
        //     if(times > 100)
        //     {
        //         break;
        //     }
        // }
        // if (1 == asocket_connect_flag)
        // {
        //     int ssl_id = 0;
        //     int timeout = 1000;
        //     con_flag = 1;
        //     int ret = cm_ssl_conn(&cm_ssl_ctx_p,ssl_id,socket,timeout);
        //     cm_demo_printf("cm_ssl_conn ret:%d\n",ret);
        //     OCTEST_FUNC_EXPECT_EQUAL_INT32(0,ret,cm_ssl_conn);
        //     con_flag = 0;
        //     asocket_connect_flag = 0;
        // }
        
        // ssl_id+=1;
        // if(6 == ssl_id)
        // {
        //     ssl_id = 0;
        // }
    }

    /* 删除事件循环 */
    cm_eloop_delete(eloop);
    osThreadExit();
}

static char *send_data = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\
1234567890qw";

static osThreadId_t test_asocket_thread_handle = NULL;

void cm_test_asocket_operation(unsigned char*cmd[],int len)
{
    if(0 == strncmp("INIT",cmd[2],strlen("INIT")))
    {
        /* 初始化Event Loop模块 */
        //cm_eloop_init();

        //cm_etimer_manager_init(&test_etimer_manager);
        /* 创建事件循环 */
        // eloop = cm_eloop_create(60);\
        // cm_demo_printf("eloop:%p\n",eloop);
        //cm_demo_printf("cm_asocket_init ret:%d\n",cm_asocket_init(6, eloop));

        //cm_async_dns_init(4, eloop);
        /* 创建eloop执行线程 */
        if(NULL == test_asocket_thread_handle)
        {
            eloop = cm_eloop_create(60);
            cm_demo_printf("eloop:%p\n",eloop);
            osThreadAttr_t thread_attr = {0};
            thread_attr.name = "test_eloop";
            thread_attr.stack_size = 4096;
            thread_attr.priority = osPriorityNormal;
            test_asocket_thread_handle = osThreadNew(eloop_thread_proc, NULL, &thread_attr);
        }
    }else if(0 == strncmp("ASOCKET_ELOOP",cmd[2],strlen("ASOCKET_ELOOP")))
    {
        cm_eloop_handle_t asocket_eloop = NULL;
        asocket_eloop = cm_asocket_eloop();
        cm_demo_printf("cm_asocket_eloop ret:%p\n",asocket_eloop);
        OCTEST_FUNC_EXPECT_NOT_NULL(asocket_eloop,cm_asocket_eloop);
    }
    else if(0 == strncmp("ASOCKET_OPEN_CONNECT",cmd[2],strlen("ASOCKET_OPEN_CONNECT")))
    {
        // 39.106.55.121:2057
        struct sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = inet_addr("39.106.55.121");
        //server_addr.sin_addr.s_addr = inet_addr("120.27.12.119");
        //server_addr.sin_port = htons(8006);
        server_addr.sin_port = htons(atoi(cmd[4]));

        //ipv6
        struct sockaddr_in6 server_addr6;
        memset(&server_addr6, 0, sizeof(server_addr6));
        inet6_aton("2408:400a:16a:9700:d3af:3f8b:7c2b:8b84",server_addr6.sin6_addr.un.u32_addr);
        server_addr6.sin6_family = AF_INET6;
        //server_addr6.sin6_flowinfo;
        server_addr6.sin6_len = 28;
        server_addr6.sin6_port = htons(atoi(cmd[4]));
        //server_addr6.sin6_scope_id;

        int sock = -1;
        int ret = -1;
        if(0 == strncmp("TCPIPV6",cmd[3],strlen("TCPIPV6")))
        {
            sock = cm_asocket_open(AF_INET6, SOCK_STREAM, IPPROTO_TCP, test_asocket_event, NULL);
            socket_arr[0] = sock;
            OCTEST_FUNC_EXPECT_NOT_EQUAL_INT32(-1,sock,cm_asocket_open);
            cm_demo_printf("cm_asocket_open ret(sock):%d\n",sock);
            if (-1 == sock)
            {
                cm_demo_printf("open failed\n");
                return;
            }
            ret = cm_asocket_connect(sock, (const struct sockaddr *)&server_addr6, sizeof(server_addr6));
            OCTEST_FUNC_EXPECT_LESS_OR_EQUAL_INT32(0,ret,cm_asocket_connect);
            cm_demo_printf("cm_asocket_connect ret:%d\n",ret);
        }else if(0 == strncmp("TCPIPV4",cmd[3],strlen("TCPIPV4")))
        {
            sock = cm_asocket_open(AF_INET, SOCK_STREAM, IPPROTO_TCP, test_asocket_event, NULL);
            socket_arr[1] = sock;
            OCTEST_FUNC_EXPECT_NOT_EQUAL_INT32(-1,sock,cm_asocket_open);
            cm_demo_printf("cm_asocket_open ret(sock):%d\n",sock);
            if (-1 == sock)
            {
                cm_demo_printf("open failed\n");
                return;
            }
            ret = cm_asocket_connect(sock, (const struct sockaddr *)&server_addr, sizeof(server_addr));
            OCTEST_FUNC_EXPECT_LESS_OR_EQUAL_INT32(0,ret,cm_asocket_connect);
            cm_demo_printf("cm_asocket_connect ret:%d\n",ret);
        }else if(0 == strncmp("UDPIPV6",cmd[3],strlen("UDPIPV6")))
        {
            sock = cm_asocket_open(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, test_asocket_event, NULL);
            socket_arr[2] = sock;
            OCTEST_FUNC_EXPECT_NOT_EQUAL_INT32(-1,sock,cm_asocket_open);
            cm_demo_printf("cm_asocket_open ret(sock):%d\n",sock);
            if (-1 == sock)
            {
                cm_demo_printf("open failed\n");
                return;
            }
            ret = cm_asocket_connect(sock, (const struct sockaddr *)&server_addr6, sizeof(server_addr6));
            OCTEST_FUNC_EXPECT_LESS_OR_EQUAL_INT32(0,ret,cm_asocket_connect);
            cm_demo_printf("cm_asocket_connect ret:%d\n",ret);
        }else if(0 == strncmp("UDPIPV4",cmd[3],strlen("UDPIPV4")))
        {
            sock = cm_asocket_open(AF_INET, SOCK_DGRAM, IPPROTO_UDP, test_asocket_event, NULL);
            socket_arr[3] = sock;
            OCTEST_FUNC_EXPECT_NOT_EQUAL_INT32(-1,sock,cm_asocket_open);
            cm_demo_printf("cm_asocket_open ret(sock):%d\n",sock);
            if (-1 == sock)
            {
                cm_demo_printf("open failed\n");
                return;
            }
            ret = cm_asocket_connect(sock, (const struct sockaddr *)&server_addr, sizeof(server_addr));
            OCTEST_FUNC_EXPECT_LESS_OR_EQUAL_INT32(0,ret,cm_asocket_connect);
            cm_demo_printf("cm_asocket_connect ret:%d\n",ret);
        }
        else if(0 == strncmp("SSL_IPV6",cmd[3],strlen("SSL_IPV6")))
        {
            inet6_aton("2408:400a:16a:9700:d3af:3f8b:7c2b:8b84",server_addr6.sin6_addr.un.u32_addr);
            server_addr6.sin6_port = htons(atoi(cmd[4]));
            sock = cm_asocket_open(AF_INET6, SOCK_STREAM, IPPROTO_TCP, test_asocket_event, NULL);
            socket_arr[0] = sock;
            OCTEST_FUNC_EXPECT_NOT_EQUAL_INT32(-1,sock,cm_asocket_open);
            cm_demo_printf("cm_asocket_open ret(sock):%d\n",sock);
            if (-1 == sock)
            {
                cm_demo_printf("open failed\n");
                return;
            }
            ret = cm_asocket_connect(sock, (const struct sockaddr *)&server_addr6, sizeof(server_addr6));
            OCTEST_FUNC_EXPECT_LESS_OR_EQUAL_INT32(0,ret,cm_asocket_connect);
            cm_demo_printf("cm_asocket_connect ret:%d\n",ret);
            con_flag = 1;
        }
        else if(0 == strncmp("SSL_IPV4",cmd[3],strlen("SSL_IPV4")))
        {
            server_addr.sin_addr.s_addr = inet_addr("39.106.55.121");
            server_addr.sin_port = htons(9999);
            sock = cm_asocket_open(AF_INET, SOCK_STREAM, IPPROTO_TCP, test_asocket_event, NULL);
            socket_arr[0] = sock;
            OCTEST_FUNC_EXPECT_NOT_EQUAL_INT32(-1,sock,cm_asocket_open);
            cm_demo_printf("cm_asocket_open ret(sock):%d\n",sock);
            if (-1 == sock)
            {
                cm_demo_printf("open failed\n");
                return;
            }
            ret = cm_asocket_connect(sock, (const struct sockaddr *)&server_addr, sizeof(server_addr));
            OCTEST_FUNC_EXPECT_LESS_OR_EQUAL_INT32(0,ret,cm_asocket_connect);
            cm_demo_printf("cm_asocket_connect ret:%d\n",ret);
            con_flag = 1;
        }
        else{
            cm_demo_printf("param error!\n");
        }

        if (ret < 0)
        {
            if (EINPROGRESS == errno)
            {
                cm_demo_printf("sock(%d) open request success, wait connect...\n", sock);
            }
            else
            {
                cm_demo_printf("sock(%d) connect failed(%d)\n", sock, errno);
            }
        }
        else if (0 == ret)
        {
            cm_demo_printf("sock(%d) connect_ok\n", sock);
        }
    }
    else if(0 == strncmp("OPEN_WITH_SOCK",cmd[2],strlen("OPEN_WITH_SOCK")))
    {
        //int cm_asocket_open_with_sock(int sock, cm_asocket_event_cb event_cb, void *cb_param);
        cm_demo_printf("server api, can not test\n");
    }else if(0 == strncmp("ACCEPT",cmd[2],strlen("ACCEPT")))
    {
        //int cm_asocket_accept(int sock, struct sockaddr *addr, socklen_t *addr_len,cm_asocket_event_cb event_cb, void *cb_param);
        cm_demo_printf("server api, can not test\n");
    }
    else if(0 == strncmp("LISTEN",cmd[2],strlen("LISTEN")))
    {
        //int cm_asocket_listen(int sock, int backlog);
        cm_demo_printf("server api, can not test\n");
    }else if(0 == strncmp("CLOSE",cmd[2],strlen("CLOSE")))
    {
        int sock = atoi(cmd[3]);
        int close_ret = cm_asocket_close(sock);
        cm_demo_printf("cm_asocket_close ret:%d\n",close_ret);
        OCTEST_FUNC_EXPECT_EQUAL_INT32(0,close_ret,cm_asocket_close);
    }
    else if(0 == strncmp("SUITE_CLOSE",cmd[2],strlen("SUITE_CLOSE")))//用于模组自动运行测试关闭打开的端口
    {
        int close_ret = cm_asocket_close(socket_arr[0]);
        cm_demo_printf("cm_asocket_close ret:%d\n",close_ret);
        OCTEST_FUNC_EXPECT_EQUAL_INT32(0,close_ret,cm_asocket_close);
        close_ret = cm_asocket_close(socket_arr[1]);
        cm_demo_printf("cm_asocket_close ret:%d\n",close_ret);
        OCTEST_FUNC_EXPECT_EQUAL_INT32(0,close_ret,cm_asocket_close);
        close_ret = cm_asocket_close(socket_arr[2]);
        cm_demo_printf("cm_asocket_close ret:%d\n",close_ret);
        OCTEST_FUNC_EXPECT_EQUAL_INT32(0,close_ret,cm_asocket_close);
        close_ret = cm_asocket_close(socket_arr[3]);
        cm_demo_printf("cm_asocket_close ret:%d\n",close_ret);
        OCTEST_FUNC_EXPECT_EQUAL_INT32(0,close_ret,cm_asocket_close);
    }
    else if(0 == strncmp("SEND",cmd[2],strlen("SEND")))
    {
        int sock = atoi(cmd[3]);
        int ret = cm_asocket_send(sock, send_data, strlen(send_data), 0);
        OCTEST_FUNC_EXPECT_GREATER_OR_EQUAL_INT32(0,ret,cm_asocket_send);
        if (ret > 0)
        {
            cm_demo_printf("sock(%d) send len=%d\n", sock, ret);
        }
        else
        {
            cm_demo_printf("sock(%d) send error(%d)\n", sock, ret);
        }
    }
    else if(0 == strncmp("SUITE_SEND",cmd[2],strlen("SUITE_SEND")))//用于模组自动运行测试发送数据
    {
        int ret = cm_asocket_send(socket_arr[0], send_data, strlen(send_data), 0);
        OCTEST_FUNC_EXPECT_GREATER_OR_EQUAL_INT32(0,ret,cm_asocket_send);
        if (ret > 0)
        {
            cm_demo_printf("sock(%d) send len=%d\n", socket_arr[0], ret);
        }
        else
        {
            cm_demo_printf("sock(%d) send error(%d)\n", socket_arr[0], ret);
        }
        osDelay(200);
        ret = cm_asocket_send(socket_arr[1], send_data, strlen(send_data), 0);
        OCTEST_FUNC_EXPECT_GREATER_OR_EQUAL_INT32(0,ret,cm_asocket_send);
        if (ret > 0)
        {
            cm_demo_printf("sock(%d) send len=%d\n", socket_arr[1], ret);
        }
        else
        {
            cm_demo_printf("sock(%d) send error(%d)\n", socket_arr[1], ret);
        }
        osDelay(200);
        ret = cm_asocket_send(socket_arr[2], send_data, strlen(send_data), 0);
        OCTEST_FUNC_EXPECT_GREATER_OR_EQUAL_INT32(0,ret,cm_asocket_send);
        if (ret > 0)
        {
            cm_demo_printf("sock(%d) send len=%d\n", socket_arr[2], ret);
        }
        else
        {
            cm_demo_printf("sock(%d) send error(%d)\n", socket_arr[2], ret);
        }
        osDelay(200);
        ret = cm_asocket_send(socket_arr[3], send_data, strlen(send_data), 0);
        OCTEST_FUNC_EXPECT_GREATER_OR_EQUAL_INT32(0,ret,cm_asocket_send);
        if (ret > 0)
        {
            cm_demo_printf("sock(%d) send len=%d\n", socket_arr[3], ret);
        }
        else
        {
            cm_demo_printf("sock(%d) send error(%d)\n", socket_arr[3], ret);
        }
        osDelay(200);
    }
    else{
        cm_demo_printf("param error!\n");
    }
    //osDelay(5);
}
